package cn.anicert.zk.util;

import java.util.List;

import javax.annotation.PostConstruct;

import org.I0Itec.zkclient.ZkClient;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import cn.anicert.zk.bean.Node;

/**
 * zookeeper的方法封装
 * @author chenzuyi
 *
 */
@Component
public class ZooKeeperUtil {
    private static final Logger LOG = LoggerFactory.getLogger(ZooKeeperUtil.class);
    @Value("${zk.connectString}")
    private String              connectString;
    
    @Value("${zk.sessionTimeout}")
    private int                 sessionTimeout;
    
    @Value("${zk.connectionTimeout}")
    private int                 connectionTimeout;
    
    private static ZkClient     zkc;
    
    @PostConstruct
    public void initZK() {
        zkc = new ZkClient(connectString, sessionTimeout, connectionTimeout);
        zkc.setZkSerializer(new StringSerializer());
    }
    
    /**
     * 与zookeeper进行连接
     * @param connectString
     * @param sessionTimeout
     * @param watcher
     * @return
     */
    public static ZkClient connectZookeeper(String connectString, int sessionTimeout,
        int connectionTimeout) {
        try {
            zkc = new ZkClient(connectString, sessionTimeout, connectionTimeout);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return zkc;
    }
    
    /**
     * 关闭连接
     * @param zk
     */
    public static void close() {
        if (zkc != null) {
            zkc.close();
        }
    }
    
    /**
     * 更新节点内容
     * @param path 节点路径
     * @param data 节点数据
     * @return
     */
    public static boolean updateZKNodeData(String path, String data) {
        try {
            zkc.writeData(path, data);
            LOG.info("更新节点数据成功，path:" + path + "  data:" + data);
            return true;
        } catch (Exception e) {
            LOG.error("更新节点数据失败：" + e.getMessage() + "，path:" + path, e);
        }
        return false;
    }
    
    /**
     * 读取指定节点的内容
     * @param path 指定的路径
     * @return
     */
    public static Node readData(String path) {
        Node node = null;
        try {
            String data = zkc.readData(path);
            /*if (data == null) {
                data = "null";
            }*/
            node = new Node();
            node.setNodePath(path);
            node.setNodeValue(data);
            LOG.debug("读取数据成功，其中path:" + path + ", data-content:" + data);
        } catch (Exception e) {
            LOG.error("读取数据失败,Exception! path: " + path + ", errMsg:" + e.getMessage(), e);
        }
        return node;
    }
    
    /**
     * 创建节点（CreateMode为PERSISTENT持久化节点）
     * @param zk zookeeper
     * @param node  节点
     * @return
     */
    public static boolean createZNode(Node node) {
        try {
            String zkPath = zkc.create(node.getNodePath(), node.getNodeValue(),
                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            LOG.info("Zookeeper创建节点成功，节点地址：" + zkPath);
            return true;
        } catch (Exception e) {
            LOG.error("创建节点失败：" + e.getMessage() + "，path:" + node.getNodeName(), e);
        }
        return false;
        
    }
    
    /**
     * 删除一个节点 忽略版本
     * @param path 节点路径
     * @return
     */
    public static boolean deteleZKNode(String path) {
        try {
            zkc.delete(path);
            LOG.info("Zookeeper删除节点1成功，节点地址：" + path);
            return true;
        } catch (Exception e) {
            LOG.error("删除节点失败：" + e.getMessage() + ",path:" + path, e);
        }
        return false;
    }
    
    /**
     * 获取某个节点下的所有节点
     * @param path 节点路径
     * @return
     */
    public static List<String> getChild(String path) {
        try {
            List<String> list = zkc.getChildren(path);
            if (list.isEmpty()) {
                LOG.debug(path + "的路径下没有节点");
            }
            return list;
        } catch (Exception e) {
            LOG.error(
                "读取子节点数据失败,InterruptedException! path: " + path + ", errMsg:" + e.getMessage(), e);
        }
        return null;
    }
    
    /**
     * 查看当前节点是否存在
     * @param zk
     * @param path
     * @return
     */
    public static boolean isExists(String path) {
        try {
            boolean exists = zkc.exists(path);
            return exists;
        } catch (Exception e) {
            LOG.error("读取数据失败,发生InterruptedException! path: " + path + ", errMsg:" + e.getMessage(),
                e);
        }
        return false;
    }
    
    /**
    * 获取当前节点下的所有子孙节点并封装到List<Node>
    * @param zk
    * @param path
    * @return
    */
    public static List<Node> getNodeDetail(List<Node> listNodes, String path) {
        List<String> list = ZooKeeperUtil.getChild(path);
        if (list != null && list.size() > 0) {
            for (String nodeName : list) {
                String pathChildUrl = "";
                if (path.equals("/")) {
                    pathChildUrl = "/" + nodeName;
                } else {
                    pathChildUrl = path + "/" + nodeName;
                }
                Node node = ZooKeeperUtil.readData(pathChildUrl);
                if (node != null) {
                    node.setNodeName(nodeName);
                    listNodes.add(node);
                }
                getNodeDetail(listNodes, pathChildUrl);
            }
        }
        return listNodes;
    }
}
